package com.ecgsystem.panel;

import java.util.concurrent.ConcurrentLinkedQueue;

import com.ecgsystem.activity.StoredSignal;
import com.ecgsystem.constants.Constants;

import com.ecgsystem.activity.R;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Typeface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

/**
 * @author anhtuan
 * 
 */
public class Panel extends SurfaceView implements SurfaceHolder.Callback, Constants {
	/*
	 * 1 o nho 1mm voi toc do 25 mm/s 1mm = 0.04s 1mm = 4px 1s = 100 px tan so
	 * lay mau a(s) lenght = 0.04/a * 62.5 = 2.5 /a khoang cach a * 25 *
	 * PixelPerMm
	 */
	private Paint grid;
	private Paint line;
	private Paint text;
	private Paint borderline;
	private Paint linebase;
	private PanelThread _thread;
	private Bitmap _bitmap;
	private String typeECG;
	private float x[];
	private float y[];

	private int i = 0;

	private ConcurrentLinkedQueue<Float> QueueDraw;

	/**
	 * TODO Put here a description of this field.
	 */
	public static int WIDTH;
	/**
	 * TODO Put here a description of this field.
	 */
	public static int HEIGHT;

	/**
	 * TODO Put here a description of this field.
	 */
	public static float baseline;
	/**
	 * TODO Put here a description of this field.
	 */
	public static float PixelPerMm = 4;

	/**
	 * TODO Put here a description of this field.
	 */
	public static float zoom = 7;
	
	/**
	 * tan so lay mau f
	 */
	public static float fx = 0.002f;
	// so diem ve tren ca ban
	private int ARRAYLENGHT;

	/**
	 * TODO Put here a description of what this constructor does.
	 *
	 * @param context
	 */
	public Panel(Context context) {
		super(context);

		this.ARRAYLENGHT = Math.round(2.5f / fx);
		this.x = new float[this.ARRAYLENGHT];
		this.y = new float[this.ARRAYLENGHT];

		// mang toa do x

		for (int j = 0; j < this.ARRAYLENGHT; j++) {
			this.x[j] = fx * 100 * j; // 100 = 25 * PixelPerMm = 25 * 4
		}

		this.setVisibility(VISIBLE);
		this.setEnabled(true);
		this.setZOrderOnTop(false);

		this.borderline = new Paint();
		this.borderline.setColor(getResources().getColor(R.color.borderline));
		this.borderline.setStrokeWidth(10);

		this.text = new Paint();
		this.text.setColor(Color.RED);
		this.text.setTextSize(14);
		this.text.setTypeface(Typeface.DEFAULT_BOLD);

		this.grid = new Paint();
		this.grid.setColor(getResources().getColor(R.color.grid));
		this.grid.setStrokeWidth(1);

		this.line = new Paint(Paint.ANTI_ALIAS_FLAG);
		this.line.setStyle(Paint.Style.STROKE);
		this.line.setColor(getResources().getColor(R.color.line));
		this.line.setAntiAlias(true);
		this.line.setStrokeWidth(2);

		this.linebase = new Paint();
		this.linebase.setColor(Color.GRAY);
		this.linebase.setAntiAlias(true);
		this.linebase.setStrokeWidth(0.5f);
		
		this.getHolder().addCallback(this);
	}

	/**
	 * TODO Put here a description of what this method does.
	 *
	 * @param text
	 */
	public void SetText(String text) {
		this.typeECG = text;
	}

	/**
	 * TODO Put here a description of what this method does.
	 *
	 */
	public void Reset() {
		// TODO Auto-generated method stub
	}

	/**
	 * TODO Put here a description of what this method does.
	 *
	 * @param QueueDraw
	 */
	public void setQueueDraw(ConcurrentLinkedQueue<Float> QueueDraw) {
		this.QueueDraw = QueueDraw;
		SurfaceHolder _holder = getHolder();
		_holder.addCallback(this);
		this._thread = new PanelThread(_holder, this._bitmap);
	}
	
	/**
	 * TODO Put here a description of what this method does.
	 *
	 */
	public void StartDraw()
	{
		this._thread.start();

	}

	/**
	 * TODO Put here a description of what this method does.
	 *
	 */
	public void Stop() {
		if (this._thread != null && this._thread.isAlive())
			this._thread.StopRun();
	}

	/**
	 * TODO Put here a description of what this method does.
	 *
	 */
	public void Resume() {
		if (this._thread != null && this._thread.isAlive())
			this._thread.setRunning(true);
	}

	/**
	 * TODO Put here a description of what this method does.
	 *
	 */
	public void StopDraw() {
		if (this._thread != null && this._thread.isAlive()) {
			this._thread.StopRun();
		}
	}

	public void surfaceChanged(SurfaceHolder holder, int format, int width,
			int height) {
		// TODO Auto-generated method stub

		this._bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_4444);
		WIDTH = width;
		HEIGHT = height;
		baseline = HEIGHT / 2;
		
		Canvas c = null;
		try {
			c = holder.lockCanvas(null);
			synchronized (holder) {
				Draw(c, new Canvas(this._bitmap));
				c.restore();
			}
		} finally {
			if (c != null) {
				holder.unlockCanvasAndPost(c);
			}
		}

	}

	public void surfaceCreated(SurfaceHolder holder) {
		return;
	}

	public void surfaceDestroyed(SurfaceHolder holder) {
		if (this._thread != null && this._thread.isAlive()) {
			this._thread.StopRun();
		}
	}

	/**
	 * TODO Put here a description of what this method does.
	 *
	 * @param vCanvas
	 * @param iCanvas
	 */
	public void Draw(Canvas vCanvas, Canvas iCanvas) {
		// TODO Auto-generated method stub
		// Vẽ lưới n�?n
		DrawGrid(iCanvas);
		
		if (this.QueueDraw != null && StoredSignal.startDraw == true) {
			this.y[this.i] = getSignal();

			// Vòng lặp vẽ liên tiếp nối i điểm
			for (int j = 0; j < this.i; j++) {
				iCanvas.drawLine(this.x[j], this.y[j], this.x[j + 1], this.y[j + 1], this.line);
				if (this.i == this.ARRAYLENGHT - 1) {
					this.y[j] = this.y[j + 1];
				}
			}
			if (this.i < this.ARRAYLENGHT - 1) {
				this.i++;
			}
			// Xóa vẽ lại từ đầu khi đã vẽ hết khung hình
			/*
			else {
				i = 0;
			}
			*/
		}
		if (this._bitmap != null && vCanvas != null)
			vCanvas.drawBitmap(this._bitmap, 0, 0, null);
	}

	private float getSignal() {
		if (this.QueueDraw != null && !this.QueueDraw.isEmpty()) {
			float signal = baseline - this.QueueDraw.remove().floatValue()
					* zoom * 10;
			return signal;
		} else {
			StopDraw();
			return baseline;
		}
	}

	/**
	 * TODO Put here a description of what this class does.
	 *
	 * @author ANHTUAN.
	 *         Created Sep 24, 2012.
	 */
	public class PanelThread extends Thread {
		private SurfaceHolder _surfaceHolder;
		private Bitmap bitmap;
		private boolean _run = false;

		/**
		 * TODO Put here a description of what this constructor does.
		 *
		 * @param surfaceHolder
		 * @param _bitmap
		 */
		public PanelThread(SurfaceHolder surfaceHolder, Bitmap _bitmap) {
			this._surfaceHolder = surfaceHolder;
			this.bitmap = _bitmap;
			this._run = true;
		}

		/**
		 * TODO Put here a description of what this method does.
		 *
		 */
		public void StopRun() {
			// TODO Auto-generated method stub
			this._run = false;
		}

		/**
		 * TODO Put here a description of what this method does.
		 *
		 * @param run
		 */
		public void setRunning(boolean run) {
			this._run = run;
		}

		@Override
		public void run() {
			Canvas c;
			while (this._run) {
				c = null;
				try {
					Thread.sleep(2);
					c = this._surfaceHolder.lockCanvas(null);
					synchronized (this._surfaceHolder) {
						if (this.bitmap != null && c != null) {
							Draw(c, new Canvas(this.bitmap));
							c.restore();
						}
					}
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} finally {
					if (c != null) {
						this._surfaceHolder.unlockCanvasAndPost(c);
					}
				}
			}
		}
	}

	private void DrawGrid(Canvas c) {

		this._bitmap.eraseColor(getResources().getColor(R.color.background));
		float t = 0;
		while (t < WIDTH) {
			c.drawLine(t, 0, t, HEIGHT, this.grid);
			t += 5 * PixelPerMm;
		}

		// Draw horizontal line
		t = 0;
		while (t < HEIGHT) {
			c.drawLine(0, t, WIDTH, t, this.grid);
			t += 5 * PixelPerMm;
		}
		c.drawLine(WIDTH, 0, WIDTH, HEIGHT, this.borderline);
		c.drawLine(0, HEIGHT, WIDTH, HEIGHT, this.borderline);

		c.drawText(this.typeECG, 10, 20, this.text);
	}

	/**
	 * TODO Put here a description of what this method does.
	 *
	 * @param zoom
	 */
	public void Zoom(float zoom) {
		if (this._thread != null && this._thread.isAlive()) {
			if (!(((Panel.zoom < 2) && zoom < 0) || ((Panel.zoom > 10) && zoom > 0))) {
				this._thread.StopRun();

				float newZoom = Panel.zoom + zoom;
				for (int i = 0; i < this.ARRAYLENGHT; i++) {
					this.x[i] = this.x[i] / Panel.zoom * newZoom;
					this.y[i] = baseline - (baseline - this.y[i]) / Panel.zoom * newZoom;
				}
				Panel.zoom = Panel.zoom + zoom;
				PixelPerMm = PixelPerMm + zoom * (float) 0.1;
				this._thread.setRunning(true);
			}
		}
	}
}